package com.amap.flutter.map;

import android.content.Context;
import android.location.Location;
import android.os.Bundle;
import android.view.View;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.lifecycle.DefaultLifecycleObserver;
import androidx.lifecycle.LifecycleOwner;

import com.amap.flutter.map.core.MapController;
import com.amap.flutter.map.overlays.marker.MarkersController;
import com.amap.flutter.map.overlays.polygon.PolygonsController;
import com.amap.flutter.map.overlays.polyline.PolylinesController;
import com.amap.flutter.map.utils.LogUtil;
import com.shareware.common.listener.Callback;
import com.t3map.api.T3MapsInitializer;
import com.t3map.api.location.T3LocationManagerService;
import com.t3map.api.location.entity.T3MapLocation;
import com.t3map.api.map.T3Map;
import com.t3map.api.map.T3MapView;
import com.t3map.core.map.T3LocationSource;

import java.util.HashMap;
import java.util.Map;

import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.platform.PlatformView;

public class AMapPlatformView implements PlatformView, DefaultLifecycleObserver,
        ActivityPluginBinding.OnSaveInstanceStateListener, MethodChannel.MethodCallHandler {
    private static final String CLASS_NAME = "AMapPlatformView";
    private final MethodChannel methodChannel;

    private MapController mapController;
    private MarkersController markersController;
    private PolylinesController polylinesController;
    private PolygonsController polygonsController;

    private T3MapView mapView;
    private T3Map t3Map;
    private boolean disposed = false;

    private final Map<String, MyMethodCallHandler> myMethodCallHandlerMap;

    AMapPlatformView(int id, Context context, BinaryMessenger binaryMessenger,
                     LifecycleProvider lifecycleProvider) {

        methodChannel = new MethodChannel(binaryMessenger, "amap_flutter_map_" + id);
        methodChannel.setMethodCallHandler(this);
        myMethodCallHandlerMap = new HashMap<>(8);

        try {
            mapView = new T3MapView(context, T3MapsInitializer.MAP_TYPE_AMAP);
            t3Map = mapView.getMap();
            mapController = new MapController(methodChannel, mapView);
            markersController = new MarkersController(methodChannel, t3Map);
            polylinesController = new PolylinesController(methodChannel, t3Map);
            polygonsController = new PolygonsController(methodChannel, t3Map);
            initMyMethodCallHandlerMap();
            lifecycleProvider.getLifecycle().addObserver(this);
            setTencentLocation();
        } catch (Throwable e) {
            LogUtil.e(CLASS_NAME, "<init>", e);
        }
    }

    private T3LocationSource.OnLocationChangedListener locationChangedListener;

    private final Callback<T3MapLocation> callback = new Callback<T3MapLocation>() {
        @Override
        public void call(T3MapLocation result) {
            if (locationChangedListener != null && result != null) {
                Location location = new Location(result.getLocationType() + "");
                //设置经纬度以及精度
                location.setLatitude(result.getLat());
                location.setLongitude(result.getLng());
                location.setAccuracy(result.getAccuracy());
                try {
                    location.setBearing(result.getBearing());
                } catch (Exception e) {
                    e.printStackTrace();
                }
                locationChangedListener.onLocationChanged(location);
            }
        }
    };

    private void setTencentLocation() {
        T3LocationManagerService.getInstance(T3MapsInitializer.MAP_TYPE_TENCENT).initSeriesLocation(6000);
        T3LocationSource locationSource = new T3LocationSource() {
            @Override
            public void activate(OnLocationChangedListener onLocationChangedListener) {
                locationChangedListener = onLocationChangedListener;
                T3LocationManagerService.getInstance(T3MapsInitializer.MAP_TYPE_TENCENT).startSeriesLocation(callback);
            }

            @Override
            public void deactivate() {
                T3LocationManagerService.getInstance(T3MapsInitializer.MAP_TYPE_TENCENT).stopSeriesLocation(callback);
            }
        };
        //设置定位源
        if (t3Map != null) {
            t3Map.setLocationSource(locationSource);
        }
    }

    private void initMyMethodCallHandlerMap() {
        String[] methodIdArray = mapController.getRegisterMethodIdArray();
        if (null != methodIdArray) {
            for (String methodId : methodIdArray) {
                myMethodCallHandlerMap.put(methodId, mapController);
            }
        }

        methodIdArray = markersController.getRegisterMethodIdArray();
        if (null != methodIdArray) {
            for (String methodId : methodIdArray) {
                myMethodCallHandlerMap.put(methodId, markersController);
            }
        }

        methodIdArray = polylinesController.getRegisterMethodIdArray();
        if (null != methodIdArray) {
            for (String methodId : methodIdArray) {
                myMethodCallHandlerMap.put(methodId, polylinesController);
            }
        }

        methodIdArray = polygonsController.getRegisterMethodIdArray();
        if (null != methodIdArray) {
            for (String methodId : methodIdArray) {
                myMethodCallHandlerMap.put(methodId, polygonsController);
            }
        }
    }


    public MapController getMapController() {
        return mapController;
    }

    public MarkersController getMarkersController() {
        return markersController;
    }

    public PolylinesController getPolylinesController() {
        return polylinesController;
    }

    public PolygonsController getPolygonsController() {
        return polygonsController;
    }


    @Override
    public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
        LogUtil.i(CLASS_NAME, "onMethodCall==>" + call.method + ", arguments==> " + call.arguments);
        String methodId = call.method;
        MyMethodCallHandler myMethodCallHandler = myMethodCallHandlerMap.get(methodId);
        if (myMethodCallHandler != null) {
            myMethodCallHandler.doMethodCall(call, result);
        } else {
            LogUtil.w(CLASS_NAME, "onMethodCall, the methodId: " + call.method + ", not implemented");
            result.notImplemented();
        }
    }


    @Override
    public void onCreate(@NonNull LifecycleOwner owner) {
        LogUtil.i(CLASS_NAME, "onCreate==>");
        try {
            if (disposed) {
                return;
            }
            if (null != mapView) {
                mapView.onCreate(null);
            }
        } catch (Throwable e) {
            LogUtil.e(CLASS_NAME, "onCreate", e);
        }
    }

    @Override
    public void onStart(@NonNull LifecycleOwner owner) {
        if (mapView != null) {
            mapView.onStart();
        }
        LogUtil.i(CLASS_NAME, "onStart==>");
    }

    @Override
    public void onResume(@NonNull LifecycleOwner owner) {
        LogUtil.i(CLASS_NAME, "onResume==>");
        try {
            if (disposed) {
                return;
            }
            if (mapView != null) {
                mapView.onResume();
            }
            if (mapController != null) {
                mapController.setMyLocationVisible(true);
            }
        } catch (Throwable e) {
            LogUtil.e(CLASS_NAME, "onResume", e);
        }
    }

    @Override
    public void onPause(@NonNull LifecycleOwner owner) {
        LogUtil.i(CLASS_NAME, "onPause==>");
        try {
            if (disposed) {
                return;
            }
            if (mapView != null) {
                mapView.onPause();
            }
            if (mapController != null) {
                mapController.setMyLocationVisible(false);
            }
        } catch (Throwable e) {
            LogUtil.e(CLASS_NAME, "onPause", e);
        }
    }

    @Override
    public void onStop(@NonNull LifecycleOwner owner) {
        LogUtil.i(CLASS_NAME, "onStop==>");
        try {
            if (disposed) {
                return;
            }
            if (mapView != null) {
                mapView.onStop();
            }
        } catch (Throwable e) {
            LogUtil.e(CLASS_NAME, "onStop", e);
        }
    }

    @Override
    public void onDestroy(@NonNull LifecycleOwner owner) {
        LogUtil.i(CLASS_NAME, "onDestroy==>");
        try {
            if (disposed) {
                return;
            }
            if (mapView != null) {
                mapView.onDestroy();
            }
        } catch (Throwable e) {
            LogUtil.e(CLASS_NAME, "onDestroy", e);
        }
    }

    @Override
    public void onSaveInstanceState(@NonNull Bundle bundle) {
        LogUtil.i(CLASS_NAME, "onDestroy==>");
        try {
            if (disposed) {
                return;
            }
            mapView.onSaveInstanceState(bundle);
        } catch (Throwable e) {
            LogUtil.e(CLASS_NAME, "onSaveInstanceState", e);
        }
    }

    @Override
    public void onRestoreInstanceState(@Nullable Bundle bundle) {
        LogUtil.i(CLASS_NAME, "onDestroy==>");
        try {
            if (disposed) {
                return;
            }
            mapView.onCreate(bundle);
        } catch (Throwable e) {
            LogUtil.e(CLASS_NAME, "onRestoreInstanceState", e);
        }
    }


    @Override
    public View getView() {
        LogUtil.i(CLASS_NAME, "getView==>");
        return mapView;
    }

    @Override
    public void dispose() {
        LogUtil.i(CLASS_NAME, "dispose==>");
        try {
            if (disposed) {
                return;
            }
            methodChannel.setMethodCallHandler(null);
            if (mapView != null) {
                mapView.onDestroy();
            }
            disposed = true;
        } catch (Throwable e) {
            LogUtil.e(CLASS_NAME, "dispose", e);
        }
    }
}
